// NewsPaperBoyClient.cpp : main source file for NewsPaperBoyClient.exe
//

#include "stdafx.h"

#include <cm\config.hpp>
#include <cm\Windows\LimitSingleInstance.h>
#include <cm\strings.hpp>
#include <cm\client_server\version.hpp>

#include "resource.h"
#include "CheckVersionDlg.h"

cm::Windows::CLimitSingleInstance g_SingleInstanceObj(_T("{EA4D2D3F-FAEB-49a8-B509-1AAD6241B5AC}")); 

CAppModule _Module;

CCheckVersionDlg CheckVersionDlg;

bool status = false;

void version_checker()
{
	HMODULE HComp;

	unsigned long current_client_version_age = 0;

	HComp = ::LoadLibrary(_T("NewsPaperBoyClientComp.dll"));
	if (HComp != NULL)
	{
		typedef unsigned long (* GetCurrentVersionApi)();

		GetCurrentVersionApi GetCurrentVersion = (GetCurrentVersionApi)::GetProcAddress(HComp,"GetCurrentVersion");
		if (GetCurrentVersion != NULL)
		{
			current_client_version_age = GetCurrentVersion();
		}

		::FreeLibrary(HComp);
	}

	// Prelevo la chiave pubblica dalle risorse
	HRSRC rsrc = ::FindResource(_Module.GetResourceInstance(),MAKEINTRESOURCE(IDR_PUBLIC_KEY),_T("KEY"));
	DWORD Size = ::SizeofResource(_Module.GetResourceInstance(), rsrc);
	HGLOBAL public_key_data_handle = ::LoadResource(_Module.GetResourceInstance(),rsrc);
	unsigned char* sign_data = (unsigned char *)::LockResource(public_key_data_handle);

	bool Connected = false;
	do
	{
		cm::client_server::version_checker::clientside_component clientside_component_checker(CheckVersionDlg);
		try
		{
			clientside_component_checker.check(host_name,port,"NewsPaperBoyClientComp.dll",sign_data,Size,current_client_version_age);
			Connected = true;
		}
		catch(const std::exception& ec)
		{
			CString Caption;
			Caption.LoadString(IDS_CAPTION);

			CString msg;
			msg.LoadString(IDS_ERROR_SERVER_OUT);
			msg += CA2T(ec.what());

			if (::MessageBox(NULL,msg,Caption,MB_RETRYCANCEL) == IDCANCEL)
			{
				UnlockResource(public_key_data_handle);
				CheckVersionDlg.PostMessage(WM_CLOSE);
				return;
			}
		}
		catch(...)
		{
			CString Caption;
			Caption.LoadString(IDS_CAPTION);

			CString msg;
			msg.LoadString(IDS_MSG_FATAL_ERROR);

			::MessageBox(NULL,msg,Caption,MB_OK | MB_ICONERROR);

			UnlockResource(public_key_data_handle);
			CheckVersionDlg.PostMessage(WM_CLOSE);
			return;
		}
	} while (Connected == false);

	UnlockResource(public_key_data_handle);
	CheckVersionDlg.PostMessage(WM_CLOSE);

	status = true;
}

void ParseCommandLine(LPCTSTR lpCmdLine) throw()
{
	cm::string::cm_string CmdLine = lpCmdLine;
	std::vector<cm::string::cm_string> result;
	boost::algorithm::split(result,CmdLine,boost::algorithm::is_any_of(_T(" ")));

	if (result.size() == 0)
	{
		return;
	}
	if (result[0] != _T(""))
	{
		host_name = CT2A(result[0].c_str());
	}

	if (result.size() == 1)
	{
		return;
	}
	if (result[1] != _T(""))
	{
		port = CT2A(result[1].c_str());
	}
}

int Run(LPTSTR lpstrCmdLine = NULL, int nCmdShow = SW_SHOWDEFAULT)
{
	ParseCommandLine(lpstrCmdLine);

	CMessageLoop theLoop;
	_Module.AddMessageLoop(&theLoop);

	if (CheckVersionDlg.Create(NULL) == NULL)
	{
		ATLTRACE(_T("Main dialog creation failed!\n"));
		return 1;
	}

	CheckVersionDlg.ShowWindow(SW_SHOWDEFAULT);

	boost::thread client_thread(boost::bind(&version_checker));

	int nRet = theLoop.Run();

	client_thread.join();

	_Module.RemoveMessageLoop();

	if (status == false)
	{
		return 1;
	}
	
	HMODULE HComp = ::LoadLibrary(_T("NewsPaperBoyClientComp.dll"));
	if (HComp == NULL)
	{
		CString Caption;
		Caption.LoadString(IDS_CAPTION);

		CString msg;
		msg.LoadString(IDS_MSG_FATAL_ERROR);

		::MessageBox(NULL,msg,Caption,MB_OK | MB_ICONERROR);

		return 1;
	}

	typedef void (* RunUserInterfaceApi)(int nCmdShow,LPCSTR HostName,LPCSTR port);

	RunUserInterfaceApi RunUserInterface = (RunUserInterfaceApi)::GetProcAddress(HComp,"RunUserInterface");
	if (RunUserInterface == NULL)
	{
		::FreeLibrary(HComp);

		CString Caption;
		Caption.LoadString(IDS_CAPTION);

		CString msg;
		msg.LoadString(IDS_MSG_FATAL_ERROR);

		::MessageBox(NULL,msg,Caption,MB_OK | MB_ICONERROR);

		return 1;
	}
	RunUserInterface(nCmdShow,host_name.c_str(),port.c_str());

	::FreeLibrary(HComp);

	return 0;
}

BOOL CALLBACK FindOtherInstance(HWND hwnd, LPARAM lParam)
{
	CString sCaption;

	int nLen = ::GetWindowTextLength(hwnd);
	::GetWindowText(hwnd, sCaption.GetBuffer(nLen + 1), nLen + 1);
	sCaption.ReleaseBuffer();

	CString aCaption;
	aCaption.LoadString(IDS_CAPTION);
	if (sCaption.Find(aCaption) != -1)
	{
		HWND* pWnd = (HWND*)lParam;
		*pWnd = hwnd;
		return FALSE;
	}

	return TRUE;
}

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR lpstrCmdLine, int nCmdShow)
{
#if	defined(_DEBUG) && defined(_WIN32_WINNT) && !defined(_AFX)
	_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
#endif

#ifdef SINGLE_INSTANCE
	if (prev_host_name == host_name && g_SingleInstanceObj.IsAnotherInstanceRunning())
	{
		HWND hWnd = NULL;
		::EnumWindows(FindOtherInstance, (LPARAM)&hWnd);
		
		// make sure its not closing
		if (hWnd != NULL)
		{
			::ShowWindow(hWnd,nCmdShow);
			::SetForegroundWindow(hWnd);
			return 0;
		}
	}
#endif

	// Bisogna mettere qui il riempimento delle voci del registy che permettono di avviare l'applicazione
	// alla partenza del computer o del login dell'utente

	// this resolves ATL window thunking problem when Microsoft Layer for Unicode (MSLU) is used
	::DefWindowProc(NULL, 0, 0, 0L);

	AtlInitCommonControls(ICC_BAR_CLASSES);	// add flags to support other controls

	HRESULT hRes = _Module.Init(NULL, hInstance);
	ATLASSERT(SUCCEEDED(hRes));

	// Inserire qui il controllo della versione e l'eventuale scaricamento

#ifdef DEBUG
	int nRet = Run(lpstrCmdLine, nCmdShow);
#endif
#ifndef DEBUG
	int nRet = Run(lpstrCmdLine, SW_HIDE);
#endif

	_Module.Term();

	return nRet;
}
